package com.pureut.equipment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pureut.equipment.domain.*;
import com.pureut.equipment.domain.dto.InspectionItemPlanDto;
import com.pureut.equipment.domain.dto.PlannedAllocationDto;
import com.pureut.equipment.domain.vo.InspectionItemPlanVo;
import com.pureut.equipment.domain.vo.InspectionWorkOrderVo;
import com.pureut.equipment.domain.vo.MaintenanceWorkOrderVo;
import com.pureut.equipment.domain.vo.ReturnDeviceStatusVo;
import com.pureut.equipment.mapper.InspectionItemMapper;
import com.pureut.equipment.mapper.InspectionItemPlanMapper;
import com.pureut.equipment.mapper.PlannedAllocationMapper;
import com.pureut.equipment.service.InspectionItemPlanService;
import com.pureut.equipment.service.InspectionWorkOrderService;
import com.pureut.equipment.service.PlannedAllocationService;
import com.pureut.equipment.util.TimeUtils;
import com.sale.common.core.exception.GlobalException;
import com.sale.common.dict.utils.DictUtils;
import com.sale.common.mybatis.core.page.PageQuery;
import com.sale.common.mybatis.core.page.TableDataInfo;
import com.sale.common.satoken.utils.LoginHelper;
import com.sale.system.api.RemoteCodeService;
import com.sale.system.api.RemoteDeviceService;
import com.sale.system.api.domain.SysDictData;
import com.sale.system.api.domain.dto.DeviceApiRecordDto;
import com.sale.system.api.domain.vo.ReturnApiDeviceStatusVo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/***
 *
 * Author:点检计划实现层
 * Date:2023/04/25 10:09
 * @DESC
 */
@Service
public class InspectionItemPlanServiceImpl extends ServiceImpl<InspectionItemPlanMapper, InspectionItemPlan> implements InspectionItemPlanService {

    /**
     * 点检计划mapper
     */
    @Resource
    InspectionItemPlanMapper inspectionItemPlanMapper;

    /**
     * 计划配置service
     */
    @Resource
    PlannedAllocationService plannedAllocationService;

    /**
     * 计划配置mapper
     */
    @Resource
    PlannedAllocationMapper plannedAllocationMapper;

    /**
     * 点检项目mapper
     */
    @Resource
    InspectionItemMapper inspectionItemMapper;

    /**
     * 点检service
     */
    @Resource
    InspectionWorkOrderService inspectionWorkOrderService;


    @DubboReference
    RemoteCodeService remoteCodeService;

    @DubboReference
    RemoteDeviceService remoteDeviceService;

    /**
     * 点检计划列表
     * @param inspectionItemPlanVo
     * @return
     */
    @Override
    public TableDataInfo<InspectionItemPlanDto> getList(InspectionItemPlanVo inspectionItemPlanVo, PageQuery pageQuery) {
        //获取状态字典
        List<SysDictData> statusArray = DictUtils.getDictCache("maintenance_plan_status");
        Map<String, String> statusMap = statusArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));

        //获取计划类型字典
        List<SysDictData> planTypeArray = DictUtils.getDictCache("planned_allocation_plan_type");
        Map<String, String> planTypeMap = planTypeArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));

        Page<InspectionItemPlanDto> list = inspectionItemPlanMapper.getList(inspectionItemPlanVo,pageQuery.build());
        List<InspectionItemPlanDto> records = list.getRecords();
        for (InspectionItemPlanDto entity : records) {
            entity.setStatusDict(statusMap.get(entity.getStatus()));
            entity.setPlanTypeDict(planTypeMap.get(entity.getPlanType()));
        }
        return TableDataInfo.build(list);
    }

    /**
     * 新增
     *
     * @param inspectionItemPlanVo
     * @return
     */
    @Override
    public boolean add(InspectionItemPlanVo inspectionItemPlanVo) throws Exception {
        //保存采购计划数据
        InspectionItemPlan inspectionItemPlan = new InspectionItemPlan();
        String authorityCoding = remoteCodeService.authorityCoding("device:spotCheck:plan:list");
        if (authorityCoding == null) {
            throw new GlobalException("该单据未进行配置，无法生成单据编码");
        }
        inspectionItemPlan.setInspectionItemPlanCode(authorityCoding)
                .setStatus(2)
                .setPlanName(inspectionItemPlanVo.getPlanName())
                .setPlanStartTime(inspectionItemPlanVo.getPlanStartTime())
                .setPlanEndTime(inspectionItemPlanVo.getPlanEndTime())
                .setInspectionItemIdStr(inspectionItemPlanVo.getInspectionItemIdStr())
                .setEquipmentIdStr(inspectionItemPlanVo.getEquipmentIdStr())
                .setCreateTime(new Date())
                .setCreateBy(LoginHelper.getUsername())
                .setDeptId(LoginHelper.getDeptId());
        boolean isBoolean = save(inspectionItemPlan);
        if (isBoolean) {
            //保存采购计划对应的计划配置项数据
            PlannedAllocation plannedAllocationData = inspectionItemPlanVo.getPlannedAllocation();

            PlannedAllocation plannedAllocation = new PlannedAllocation();
            plannedAllocation.setAllocationType(2)
                    .setExecutionInterval(plannedAllocationData.getExecutionInterval())
                    .setExecutionCycle(plannedAllocationData.getExecutionCycle())
                    .setExecutionMonth(plannedAllocationData.getExecutionMonth())
                    .setExecutionDays(plannedAllocationData.getExecutionDays())
                    .setPlanId(inspectionItemPlan.getId())
                    .setPlanType(plannedAllocationData.getPlanType())
                    .setExecutionTime(new Date());
            plannedAllocationService.save(plannedAllocation);
            //回传几乎配置id
            InspectionItemPlan byId = getById(inspectionItemPlan.getId());
            byId.setPlannedAllocationId(plannedAllocation.getId());
            updateById(byId);
            //回传设备状态
            ReturnApiDeviceStatusVo returnDeviceStatusVo = new ReturnApiDeviceStatusVo();
            returnDeviceStatusVo.setDeviceIds(inspectionItemPlanVo.getEquipmentIdStr());
            returnDeviceStatusVo.setStatus(4);
            remoteDeviceService.returnDeviceStatus(returnDeviceStatusVo);
        }
        return isBoolean;
    }

    /**
     * 删除
     *
     * @param id
     * @return
     */
    @Override
    public boolean deleteInspectionItemPlan(Long id) {
        InspectionItemPlan byId = getById(id);
        if (byId.getStatus() != 1) {
            //将计划配置数据删除
            PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getPlanId, id).eq(PlannedAllocation::getAllocationType, 2));
            boolean b = plannedAllocationService.removeById(plannedAllocation);
            if (b) {
                //删除保养计划
                removeById(byId);
            }
            return b;
        } else {
            throw new GlobalException("计划启用中，无法删除");
        }
    }

    /**
     * 修改
     *
     * @param inspectionItemPlanVo
     * @return
     */
    @Override
    public boolean updateItemPlan(InspectionItemPlanVo inspectionItemPlanVo) {
        InspectionItemPlan inspectionItemPlan = getById(inspectionItemPlanVo.getId());
        if (inspectionItemPlan.getStatus() == 2) {
            inspectionItemPlan.setPlanName(inspectionItemPlanVo.getPlanName())
                    .setPlanStartTime(inspectionItemPlanVo.getPlanStartTime())
                    .setPlanEndTime(inspectionItemPlanVo.getPlanEndTime())
                    .setInspectionItemIdStr(inspectionItemPlanVo.getInspectionItemIdStr())
                    .setEquipmentIdStr(inspectionItemPlanVo.getEquipmentIdStr());
            boolean b = updateById(inspectionItemPlan);
            if (b) {
                //获取对应的计划配置数据
                PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getPlanId, inspectionItemPlan.getId()).eq(PlannedAllocation::getAllocationType, 2));
                PlannedAllocation plannedAllocationData = inspectionItemPlanVo.getPlannedAllocation();
                plannedAllocation.setExecutionInterval(plannedAllocationData.getExecutionInterval())
                        .setExecutionCycle(plannedAllocationData.getExecutionCycle())
                        .setExecutionMonth(plannedAllocationData.getExecutionMonth())
                        .setExecutionDays(plannedAllocationData.getExecutionDays())
                        .setPlanType(plannedAllocationData.getPlanType());
                plannedAllocationService.updateById(plannedAllocation);
            }
            return b;
        } else {
            throw new GlobalException("只能修改待启用的数据");
        }
    }

    /**
     * 查看
     *
     * @param id
     * @return
     */
    @Override
    public InspectionItemPlanDto getItemPlanView(Long id) {
        InspectionItemPlanDto inspectionItemPlanDto = new InspectionItemPlanDto();
        //获取设备类型字典
        List<SysDictData> deviceTypeArray = DictUtils.getDictCache("device_type");
        Map<String, String> deviceTypeMap = deviceTypeArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));

        //获取计划单数据
        InspectionItemPlan inspectionItemPlan = getById(id);
        //获取对应的计划配置数据
        PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getId, inspectionItemPlan.getPlannedAllocationId()).eq(PlannedAllocation::getAllocationType, 2));

        //获取点检项目
        List<String> inspectionItemIds = Arrays.asList(inspectionItemPlan.getInspectionItemIdStr().split(","));
        List<InspectionItem> inspectionItems = inspectionItemMapper.selectList(new QueryWrapper<InspectionItem>().lambda().in(InspectionItem::getId, inspectionItemIds));
        inspectionItemPlanDto.setInspectionItems(inspectionItems);
        //获取关联设备
        String ids = inspectionItemPlan.getEquipmentIdStr();
        List<DeviceApiRecordDto> drvices = remoteDeviceService.getDeviceByIds(ids);
        for(DeviceApiRecordDto entity : drvices){
            //设备类型
            entity.setDeviceTypeDict(deviceTypeMap.get(entity.getDeviceType()));
        }
        inspectionItemPlanDto.setDrvices(drvices);
        //封装计划配置项
        PlannedAllocationDto plannedAllocationDto = new PlannedAllocationDto();
        //执行周期列表
        List<String> cycleList = Arrays.asList(plannedAllocation.getExecutionCycle().split(","));
        //执行月份列表
        List<String> monthList = Arrays.asList(plannedAllocation.getExecutionMonth().split(","));
        //执行日期列表
        List<String> daysList = Arrays.asList(plannedAllocation.getExecutionDays().split(","));

        plannedAllocationDto.setId(plannedAllocation.getId())
                .setPlanId(plannedAllocation.getPlanId())
                .setPlanType(plannedAllocation.getPlanType())
                .setExecutionInterval(plannedAllocation.getExecutionInterval())
                .setExecutionCycleList(cycleList)
                .setExecutionMonthList(monthList)
                .setExecutionDaysList(daysList);
        inspectionItemPlanDto.setId(inspectionItemPlan.getId());
        inspectionItemPlanDto.setPlannedAllocationDto(plannedAllocationDto);
        inspectionItemPlanDto.setInspectionItemPlanCode(inspectionItemPlan.getInspectionItemPlanCode());
        inspectionItemPlanDto.setPlanName(inspectionItemPlan.getPlanName());
        inspectionItemPlanDto.setPlanStartTime(inspectionItemPlan.getPlanStartTime());
        inspectionItemPlanDto.setPlanEndTime(inspectionItemPlan.getPlanEndTime());

        return inspectionItemPlanDto;
    }

    /**
     * 启用
     *
     * @param id
     * @return
     */
    @Override
    public boolean enable(Long id) throws Exception {
        InspectionItemPlan inspectionItemPlan = getById(id);
        long timeStart = inspectionItemPlan.getPlanStartTime().getTime();
        long timeEnd = inspectionItemPlan.getPlanEndTime().getTime();
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date nowParse = simpleDateFormat.parse(simpleDateFormat.format(date));
        long timeNow = nowParse.getTime();
        //如果当前时间大于计划结束时间，就变为已结束；如果当前时间小于计划开始时间，就变为未开始
        if (timeNow > timeEnd) {
            inspectionItemPlan.setStatus(4);
            return updateById(inspectionItemPlan);
        }
        if (timeNow < timeStart) {
            inspectionItemPlan.setStatus(5);
            return updateById(inspectionItemPlan);
        }
        if (inspectionItemPlan.getStatus() == 3 || inspectionItemPlan.getStatus() == 2) {
            inspectionItemPlan.setStatus(1);
            PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getId, inspectionItemPlan.getPlannedAllocationId()).eq(PlannedAllocation::getAllocationType, 2));
            // 若计划类型为”日”时，则在启用时立即执行一次；
            if (plannedAllocation.getPlanType() == 1) {
                if (inspectionItemPlan.getStatus() != 3) {
                    if (timeNow >= timeStart && timeNow <= timeEnd) {
                        //生成保养工单
                        InspectionWorkOrderVo inspectionWorkOrderVo = new InspectionWorkOrderVo();
                        inspectionWorkOrderVo.setInspectionItemIdStr(inspectionItemPlan.getInspectionItemIdStr());
                        inspectionWorkOrderVo.setDeviceIds(inspectionItemPlan.getEquipmentIdStr());
                        inspectionWorkOrderVo.setSubordinatePlan(inspectionItemPlan.getId());
                        inspectionWorkOrderService.addToday(inspectionWorkOrderVo);
                    }
                }
            }
            //若计划为周时候
            if (plannedAllocation.getPlanType() == 2) {
                //获取每周执行的字符串时间
                List<String> executionCycle = Arrays.asList(plannedAllocation.getExecutionCycle().split(","));
                //获取当前时间是星期几
                String i = String.valueOf(TimeUtils.dayForWeek(simpleDateFormat.format(new Date())));
                //如果当前星期几包含在周执行天数
                if (executionCycle.contains(i)) {
                    //如果可以整除，就生成对应的保养工单
                    InspectionWorkOrderVo inspectionWorkOrderVo = new InspectionWorkOrderVo();
                    inspectionWorkOrderVo.setInspectionItemIdStr(inspectionItemPlan.getInspectionItemIdStr());
                    inspectionWorkOrderVo.setDeviceIds(inspectionItemPlan.getEquipmentIdStr());
                    inspectionWorkOrderVo.setSubordinatePlan(inspectionItemPlan.getId());
                    inspectionWorkOrderService.schedulingAdd(inspectionWorkOrderVo);
                }
            }
            //若计划为月时候
            if (plannedAllocation.getPlanType() == 3) {
                List<String> monthList = Arrays.asList(plannedAllocation.getExecutionMonth().split(","));
                List<String> dayList = Arrays.asList(plannedAllocation.getExecutionDays().split(","));
                StringBuilder stringBuilder = new StringBuilder();
                for (String entityMonth : monthList) {
                    for (String entityDay : dayList) {
                        BigDecimal add = new BigDecimal(entityDay).add(new BigDecimal("1"));
                        stringBuilder.append(entityMonth).append("-").append(add).append(",");
                    }
                }
                StringBuilder dateResult = stringBuilder.deleteCharAt(stringBuilder.length() - 1);
                //获取当前时间
                SimpleDateFormat sf = new SimpleDateFormat("MM-dd");
                String format = sf.format(new Date());
                //判断当前时间是否在计划开始时间和计划结束时间之内
                boolean effectiveDate = TimeUtils.isEffectiveDate(new Date(), inspectionItemPlan.getPlanStartTime(), inspectionItemPlan.getPlanEndTime());
                if (dateResult.toString().contains(format) && effectiveDate) {
                    InspectionWorkOrderVo inspectionWorkOrderVo = new InspectionWorkOrderVo();
                    inspectionWorkOrderVo.setInspectionItemIdStr(inspectionItemPlan.getInspectionItemIdStr());
                    inspectionWorkOrderVo.setDeviceIds(inspectionItemPlan.getEquipmentIdStr());
                    inspectionWorkOrderVo.setSubordinatePlan(inspectionItemPlan.getId());
                    inspectionWorkOrderService.schedulingAdd(inspectionWorkOrderVo);
                }
            }
            return updateById(inspectionItemPlan);
        } else {
            throw new GlobalException("只能启用状态为”已停用”的计划");
        }
    }

    /**
     * 停用
     *
     * @param id
     * @return
     */
    @Override
    public boolean stop(Long id) {
        InspectionItemPlan inspectionItemPlan = getById(id);
        if (inspectionItemPlan.getStatus() == 1 || inspectionItemPlan.getStatus() == 5) {
            inspectionItemPlan.setStatus(3);
            return updateById(inspectionItemPlan);
        } else {
            throw new GlobalException("只能停用状态为”启用中”或者“未开始”的计划");
        }
    }

    /**
     * 根据计划开始时间和结束时间定时修改计划状态（定时任务调用）
     *
     * @return
     */
    @Override
    public boolean updateInspectionStatusByTime() throws ParseException {
        List<InspectionItemPlan> list = list();
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date nowParse = simpleDateFormat.parse(simpleDateFormat.format(date));
        long nowTime = nowParse.getTime();
        for (InspectionItemPlan entity : list) {
            long planEndTime = entity.getPlanEndTime().getTime();
            long planStartTime = entity.getPlanStartTime().getTime();
            if (nowTime < planStartTime || nowTime > planEndTime) {
                entity.setStatus(4);
            }
        }
        return updateBatchById(list);
    }
}
